 
/* 
 * Copyright (C) Ignacio Lucas
 */
 
/*
 *  server_worker, hecho por Ignacio Lucas
 *
 *  Librería que encpasula un worker del servidor, capaz de cambiar contextos mediante manejo de corrutinas.
 *
 *  Ignacio Lucas <ignacio.lucas@gmail.com>
 *
 */
#if !defined(SERVER_WORKER_H)
#define SERVER_WORKER_H

typedef struct s_server_worker *server_worker_t;

typedef struct s_server_worker_job * server_worker_job_t;

#define SERVER_WORKER_JOB_MAX_CHILDREN 16

#define SERVER_WORKER_JOB_OP_CHILD_FINISHED 0
#define SERVER_WORKER_JOB_OP_PARENT_WAITING 1

typedef struct s_server_worker_job_children
{
	server_worker_job_t child[SERVER_WORKER_JOB_MAX_CHILDREN];
	int count;
	
} server_worker_job_children;

// Configuraciones especificas de eventos para comunicacion entre jobs padres e hijos.
typedef struct s_server_worker_job_comm_config
{
	int	operation; // SERVER_WORKER_JOB_OP_CHILD_FINISHED: job hijo finaliza, SERVER_WORKER_JOB_OP_PARENT_WAITING: job padre a espera de finalizar sus hijos.
	server_worker_job_t job; // job que configura la operacion
	server_worker_job_children children_jobs; // en caso de operation = SERVER_WORKER_JOB_OP_PARENT_WAITING, aqui se guardan los hijos que se aguarda su finalizacion.
	int pending_children; // inicialmente tendra el valor de count del atributo children_jobs. A medida que cada hijo finaliza, se ira restando este contador. Cuando llega a cero, significa que todos los hijos finalizaron.

} server_worker_job_comm_config;

typedef server_worker_job_comm_config *server_worker_job_comm_config_t;


// Diferentes valores del atributo worker_job::status
#define SERVER_WORKER_JOB_RUNNING 			1
#define SERVER_WORKER_JOB_WAITING 			2
#define SERVER_WORKER_JOB_RUNNABLE 		3
#define SERVER_WORKER_JOB_PARENT_WAITING 	4
#define SERVER_WORKER_JOB_DONE 			5

#include "job_event.h"
#include "queue.h"
#include "logger.h"
#include "socket.h"
#include "jobs_controller.h"

// configuracion
void server_worker_set_stack_size(size_t ss);
size_t server_worker_get_stack_size();
size_t server_worker_get_server_worker_job_struct_size();


// metodos de server_worker

// inicializacion de un server worker.
server_worker_t server_worker_init(queue_t queue, jobs_controller_t jc, int id);

// devuelve la tarea que esta ejecutando actualmente un server_worker.
server_worker_job_t server_worker_get_current_job(server_worker_t swt);

// destruccion de un server_worker
int server_worker_destroy(server_worker_t wk);

// metodos de server_worker_job (tareas que ejecuta el server_worker)

// crear una nueva tarea.
server_worker_job_t server_worker_job_init();

// setea el valor de prioridad de ejecucion.
int server_worker_job_set_launch_priority(server_worker_job_t job_t, int launch_priority);

// devuelve el valor de prioridad de ejecucion.
int server_worker_job_get_launch_priority(server_worker_job_t job_t);

// resetear el estado de una tarea.
int server_worker_job_reset(server_worker_job_t job_t);

// setea la funcion que representa la aplicacion del usuario. Esa funcion es la tarea a realizar.
void server_worker_job_set_proc(server_worker_job_t job_t, 	int (*proc)(server_worker_job_t,void *));

// devuelve la funcion correspondiente a la tarea a realizar.
void* server_worker_job_get_proc(server_worker_job_t job_t);

// setea parametros pasados a la funcion que representa la tarea a realizar.
void server_worker_job_set_args(server_worker_job_t job_t, 	void *args);

// devuelve los parametros pasados a la funcion que representa la tarea a realizar.
void* server_worker_job_get_args(server_worker_job_t job_t);

// setea datos que la aplicacion quiera resguardar a nivel de la tarea (variable global a la tarea).
void server_worker_job_set_user_data(server_worker_job_t job_t, void *user_data);

// devuelve los datos que la aplicacion resguarda a nivel de la tarea (variable global a la tarea).
void* server_worker_job_get_user_data(server_worker_job_t job_t);

// devuelve el server_worker que esta ejecutando la tarea job_t.
server_worker_t server_worker_job_get_server_worker(server_worker_job_t job_t);

// setea el estado de ejecucion de la tarea (ver constantes SERVER_WORKER_JOB_* en este archivo).
void server_worker_job_set_status(server_worker_job_t job_t, int status);

// devuelve el estado de ejecucion de la tarea.
int server_worker_job_get_status(server_worker_job_t job_t);

// destruye una tarea.
int server_worker_job_destroy(server_worker_job_t job_t);

// loguea un mensaje en el contexto de una tarea.
//int server_worker_job_log(server_worker_job_t job_t, enum LOG_LEVEL log_level, char *msg);

// loguea un mensaje formateado en el contexto de una tarea.
//int server_worker_job_log_fmt(server_worker_job_t job_t, enum LOG_LEVEL log_level, char *fmt, ...);

// detiene una tarea en ejecucion.
void server_worker_job_stop(server_worker_job_t job_t);

// punto de registro de evento de interes y cambio de contexto a otra corrutina.
int server_worker_job_register_event_and_stop(server_worker_job_t job_t, int source, void *source_config, int events);

// devuelve el evento pendiente de configuracion que tenga una tarea.
job_event_t server_worker_job_get_outstanding_event(server_worker_job_t job_t);

// devuelve 1 si server_worker_job_get_status() == SERVER_WORKER_JOB_WAITING
int server_worker_job_is_outstanding_event(server_worker_job_t job_t);

// devuelve el padre que lanzo al proceso job_t. Si no hay padre, devuelve NULL.
server_worker_job_t server_worker_job_get_parent(server_worker_job_t job_t);

// devuelve la configuracion de job_comm para un job particular. Solo tendra sentido cuando job_t es un job padre que tiene configurado jobs hijos sobre los que esta esperando su finalizacion.
server_worker_job_comm_config_t  server_worker_job_get_job_comm_config(server_worker_job_t job_t);


// metodos para lanzar jobs desde un job y esperar su finalizacion.
server_worker_job_t server_worker_job_prepare(server_worker_job_t parent_job, int (*server_implementation)(server_worker_job_t,void *), void *args);
server_worker_job_t server_worker_job_prepare_priority(server_worker_job_t parent_job, int (*server_implementation)(server_worker_job_t,void *), void *args,int priority);
int server_worker_job_wait_children(server_worker_job_t parent_job, server_worker_job_children *children);

#endif
